
package com.huawei.chengdu.meetingdemo.presenter;

import android.os.Message;

import com.device.idea.meeting.CallCtrl.model.CallStatus;
import com.device.idea.meeting.CallCtrl.model.ConfState;
import com.device.idea.meeting.ConfCtrl.model.ParticipantInfo;
import com.device.idea.meeting.ConfCtrl.model.TermCtrlSiteInfo;
import com.device.idea.meeting.MeetingCallback;
import com.device.idea.meeting.Share.model.ShareCurInfo;
import com.huawei.chengdu.meetingdemo.consts.ObserverConts;
import com.huawei.chengdu.meetingdemo.util.AppContext;
import com.huawei.chengdu.meetingdemo.util.GlobalHandler;
import com.huawei.chengdu.meetingdemo.util.GlobalHandlerAdapter;
import com.huawei.chengdu.meetingdemo.util.LogUtil;
import com.huawei.chengdu.meetingdemo.util.ScreenUtil;
import com.huawei.chengdu.meetingdemo.util.SearchSiteThread;
import com.huawei.chengdu.meetingdemo.view.IViewDataObserver;
import com.huawei.chengdu.meetingdemo.view.dialogs.CustomFloatWindow;
import com.huawei.chengdu.meetingdemo.view.dialogs.FloatWindowBase;
import com.huawei.chengdu.meetingdemo.view.dialogs.ViewsFactory;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;

public class MeetingManager {
    private static final String TAG = MeetingManager.class.getSimpleName();

    private ConfState confState = ConfState.NONE;

    private SearchSiteThread searchSiteThread; // 地址本搜索线程

    private AddressBookPresenter addressBookPresenter;

    private static volatile MeetingManager instance = null;

    private Map<Integer, List<IViewDataObserver>> rbObservedList;

    private GlobalHandler msgHandler;

    private CopyOnWriteArrayList<ParticipantInfo> participantInfoList = new CopyOnWriteArrayList<>();

    private final List<Consumer<ConfState>> confStateListeners = new CopyOnWriteArrayList<>();

    private TermCtrlSiteInfo termCtrlSiteInfo;

    public static MeetingManager getInstance() {
        if (instance == null) {
            synchronized (MeetingManager.class) {
                if (instance == null) {
                    instance = new MeetingManager();
                }
            }
        }
        return instance;
    }

    private MeetingManager() {
        LogUtil.info(TAG + " MeetingManager init");
        addressBookPresenter = new AddressBookPresenter();
        msgHandler = GlobalHandler.getInstance();
        rbObservedList = new HashMap<>();
    }

    /**
     * 是否为点对点会议
     *
     * @return true 是
     */
    public boolean isJoinConfStateP2P() {
        boolean isJoinConfP2P = confState == ConfState.CONF;
        LogUtil.info(TAG + " isJoinConfStateP2P isJoinConfP2P=" + isJoinConfP2P);
        return isJoinConfP2P;
    }

    /**
     * 会议信息
     *
     * @return CallStatus 会议信息
     */
    public CallStatus getCallStatus() {
        CallStatus status = ConfSdkPresenter.getCallStatus();
        LogUtil.info(TAG + " getCallStatus status=" + status);
        return status;
    }

    /**
     * 联系人开始搜索会场
     *
     * @param inputStr   输入会场关键字
     * @param isAutoFlag 是否自动搜索
     */
    public void startSearchSite(String inputStr, boolean isAutoFlag) {
        // 搜索LDAP记录时，最多是128
        int bytes = 0;
        try {
            bytes = inputStr.trim().getBytes("UTF-8").length;
        } catch (UnsupportedEncodingException e) {
            LogUtil.error(TAG + " startSearchSite getBytes error=" + e);
        }
        if (inputStr.length() > 128 || bytes > 128) {
            AppContext.instance().rbServ.searchAddrBookUserList.clear();
            AppContext.instance().rbServ.noticeDataChange(ObserverConts.DATA_LOCAL_AND_LDAP_SEARCH_SITE, null);
            return;
        }
        if ((searchSiteThread != null && searchSiteThread.isAlive())) {
            LogUtil.debug(TAG + " searchSiteThread isAlive");
            searchSiteThread.interrupt();
            searchSiteThread = null;
        }
        searchSiteThread = new SearchSiteThread(inputStr, AddressBookPresenter.SEARCH_MEETING, isAutoFlag);
        searchSiteThread.start();
    }

    /**
     * 搜索LDAP和本地会场
     *
     * @param str          搜索关键字
     * @param searchSource 操作码
     * @param isAutoFlag   是否页面加载搜索
     */
    public void searchLocalAndLDAPSiteList(String str, int searchSource, boolean isAutoFlag) {
        if (addressBookPresenter == null) {
            LogUtil.error(TAG + " searchLocalAndLDAPSiteList() addressBookPresenter is null");
            return;
        }
        addressBookPresenter.addressBookSearch(str, searchSource, isAutoFlag);
    }

    /**
     * 处理数据变化了，通知界面数据进行更新
     *
     * @param id      消息ID
     * @param message 制定类型的观察者
     */
    public void noticeDataChange(int id, Message message) {
        // 取出指定类型的观察者列表
        List<IViewDataObserver> observerList = rbObservedList.get(id);
        // 没有观察者，就退出
        if (observerList == null) {
            LogUtil.info(TAG + " observerList == null");
            return;
        }
        GlobalHandlerAdapter msgData;
        Message msg;
        for (IViewDataObserver uiView : observerList) {
            if (uiView == null) {
                LogUtil.info(TAG + " uiView == null");
                continue;
            }
            if (message == null) {
                msgData = new GlobalHandlerAdapter(uiView, id, null);
            } else {
                msgData = new GlobalHandlerAdapter(uiView, id, message.obj);
            }
            msg = Message.obtain();
            msg.obj = msgData;
            msgHandler.sendMessage(msg);
            LogUtil.info(TAG + " msgHandler.sendMessage(msg) id:" + id);
        }
    }

    /**
     * 注册记录本的观察者，如果记录本发生了变化，就需要通知观察者列表。
     *
     * @param id  ID
     * @param obj 注册界面
     */
    public void registerObserved(int id, IViewDataObserver obj) {
        List<IViewDataObserver> observerList = rbObservedList.get(id);

        if (observerList == null) {
            observerList = new ArrayList<>();
            rbObservedList.put(id, observerList);
        }
        if (!observerList.contains(obj)) {
            observerList.add(obj);
            LogUtil.debug(TAG + " observerList.add(obj)");
        }
    }

    /**
     * 反注册
     *
     * @param listener 界面类型
     */
    public synchronized void unregistDataChangeListenerObj(IViewDataObserver listener) {
        Iterator<Map.Entry<Integer, List<IViewDataObserver>>> iters = rbObservedList.entrySet().iterator();
        while (iters.hasNext()) {
            Map.Entry<Integer, List<IViewDataObserver>> entry = iters.next();
            List<IViewDataObserver> observers = entry.getValue();
            if (observers == null) {
                continue;
            }
            int loc = -1;
            for (int i = 0; i < observers.size(); i++) {
                if (listener == observers.get(i)) {
                    loc = i;
                    break;
                }
            }
            if (loc != -1) {
                observers.remove(loc);
            }
        }
    }

    public AddressBookPresenter getAddressBookPresenter() {
        return addressBookPresenter;
    }

    /**
     * 判断当前是否会议中
     *
     * @return true 会议中
     */
    public boolean isInConf() {
        return ConfState.CONF.equals(confState) || ConfState.CONFCTRL.equals(confState) ||
                ConfState.MULTISTREAMCAP.equals(confState);
    }

    /**
     * 本会场是否是主席
     *
     * @return true 是
     */
    public boolean isMeChairman() {
        return ConfSdkPresenter.isChairman();
    }

    /**
     * 其他会场是否存在主席
     *
     * @return true 存在
     */
    public boolean isHasChairman() {
        return ConfSdkPresenter.isHasChairman();
    }

    public void callAttendee(String siteName, int userId, MeetingCallback callback) {
        ConfSdkPresenter.callAttendee(siteName, userId, callback);
    }

    public void quietAttendee(int userId, boolean isQuiet, MeetingCallback callback) {
        ConfSdkPresenter.quietAttendee(userId, isQuiet, callback);
    }

    /**
     * 本地会场的uerid
     *
     * @return true 是
     */
    public int getLocalUserId() {
        LogUtil.info(TAG + "getLocalUserId()");

        termCtrlSiteInfo = ConfSdkPresenter.getTermCtrlSiteInfo();
        if (termCtrlSiteInfo == null) {
            LogUtil.error(TAG + "getLocalUserId, siteInfo is null");
            return -1;
        }
        int localUserIfd = termCtrlSiteInfo.getLocalUserId();
        LogUtil.info(TAG + "getLocalUserId() localUserIfd:" + localUserIfd);
        return localUserIfd;
    }

    public void hangUpAttendee(int userId, MeetingCallback callback) {
        ConfSdkPresenter.hangUpAttendee(userId, callback);
    }

    public void watchAttendee(int userId, MeetingCallback callback) {
        ConfSdkPresenter.watchAttendee(userId, callback);
    }

    public void watchMultiPic(MeetingCallback callback) {
        ConfSdkPresenter.watchMultiPic(callback);
    }

    /**
     * 多点会议中，返回本地缓存的会场列表
     *
     * @return list数据
     */
    public List<ParticipantInfo> getParticipantListInCache() {
        return participantInfoList;
    }

    public void setParticipantList(List<ParticipantInfo> list) {
        participantInfoList.clear();
        participantInfoList.addAll(list);
    }

    /**
     * 与会者信息列表刷新指示
     *
     * @param list 与会者信息
     */
    public void onConfctrlUpdateSiteListNotify(List<ParticipantInfo> list) {
        if (list == null) {
            LogUtil.error(TAG + " onConfctrlUpdateSiteListNotify error, list is null");
            return;
        }
        LogUtil.info(TAG + " onConfctrlUpdateSiteListNotify: " + list.size());

        // CtrlSiteInfo和与会者列表都要更新，都放到超时定时器里处理
        participantInfoList.clear();
        participantInfoList.addAll(list);
        termCtrlSiteInfo = ConfSdkPresenter.getTermCtrlSiteInfo();
        noticeDataChange(ObserverConts.MSG_ATTENDESS_CHANGE_STATUS, Message.obtain());
        LogUtil.info(TAG + " updateSiteListTimer noticeDataChange");
    }

    public TermCtrlSiteInfo getTermCtrlSiteInfo() {
        return ConfSdkPresenter.getTermCtrlSiteInfo();
    }

    /**
     * 是否为多流会议
     *
     * @return 布尔值
     */
    public boolean isJoinConfStateMultiStream() {
        boolean isJoinConfMultiStream = confState == ConfState.MULTISTREAMCAP;
        LogUtil.info(TAG + " isJoinConfStateMultiStream confState=" + confState);
        return isJoinConfMultiStream;
    }

    public void applyChairmanAuthority(String code, MeetingCallback callback) {
        ConfSdkPresenter.applyChairmanAuthority(code, callback);
    }

    public void muteAllAttendee(boolean isMute, MeetingCallback callback) {
        ConfSdkPresenter.muteAllAttendee(isMute, callback);
    }

    public int getConfLeftTime() {
        return ConfSdkPresenter.getConfLeftTime();
    }

    public void postponeConference(int time, MeetingCallback callback) {
        ConfSdkPresenter.postponeConference(time, callback);
    }

    /**
     * 共享中信息
     *
     * @return 共享中信息实体
     */
    public ShareCurInfo getCurShareInfo() {
        return ConfSdkPresenter.getCurShareInfo();
    }

    public void onConfStateChangeNotify(ConfState state) {
        LogUtil.info(TAG + " onConfStateChangeNotify state:" + state);
        confState = state;
        CustomFloatWindow.hideAllFloatWindow();
        FloatWindowBase.releaseAllWindows();
        if (ConfState.NONE.equals(state)) {
            ScreenUtil.clearBindInfo();
            ViewsFactory.destory();
        }
        msgHandler.post(() -> confStateListeners.forEach(it -> it.accept(state)));
    }

    /**
     * 注册会议状态变化共享监听
     *
     * @param listener 监听器
     */
    public void addConfStateListener(Consumer<ConfState> listener) {
        confStateListeners.add(listener);
    }

    public int addVideoResponse(boolean isAccept) {
        return ConfSdkPresenter.addVideoResponse(isAccept);
    }
}